﻿/*              Copyright(c) 2008 Dave Sexton              *
 * http://www.codeplex.com/DocProject                      *
 * http://www.codeplex.com/DocProject/Project/License.aspx *
 ***********************************************************/
using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;

namespace DaveSexton.DocToMaml.Extensions
{
	internal static class XmlExtensions
	{
		/// <summary>
		/// Writes the subtree of the specified <paramref name="reader"/>, including the current element, to the specified <paramref name="writer"/>.
		/// </summary>
		/// <remarks>
		/// This method differs from <see cref="XmlWriter.WriteNode"/> in that it will not write XML namespace attributes that
		/// are currently in scope.  <see cref="XmlWriter.WriteNode"/> will write all XML namespace attributes, regardless of whether
		/// they have already been defined earlier by the <paramref name="writer"/>.
		/// </remarks>
		public static void WriteNode(this XmlWriter writer, XmlReader reader)
		{
			while (!reader.EOF)
			{
				switch (reader.NodeType)
				{
					case XmlNodeType.Element:
						writer.WriteStartElement(reader);
						break;
					case XmlNodeType.EndElement:
						writer.WriteEndElement();
						reader.Read();
						break;
					default:
						writer.WriteNode(reader, false);
						break;
				}
			}
		}

		public static void WriteStartElement(this XmlWriter writer, XmlReader reader)
		{
			writer.WriteStartElement(reader.Prefix, reader.LocalName, reader.NamespaceURI);

			writer.WriteAttributes(reader);

			if (reader.IsEmptyElement)
				writer.WriteEndElement();

			reader.Read();
		}

		public static void WriteAttributes(this XmlWriter writer, XmlReader reader)
		{
			while (reader.MoveToNextAttribute())
			{
				if (!IsInScopeNamespaceDefinition(writer, reader))
					writer.WriteAttributeString(reader.Prefix, reader.LocalName, reader.NamespaceURI, reader.Value);
			}

			reader.MoveToElement();
		}

		[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1820:TestForEmptyStringsUsingStringLength")]
		private static bool IsInScopeNamespaceDefinition(XmlWriter writer, XmlReader reader)
		{
			if (reader.Prefix == "xmlns")
			{
				if (writer.LookupPrefix(reader.Value) == reader.LocalName)
					return true;
			}
			else if (reader.Name == "xmlns")
			{
				if (writer.LookupPrefix(reader.Value) == "")
					return true;
			}

			return false;
		}
	}
}
